<?php

namespace App\Service\Check\KfDataSource;

use App\Enums\Check\CheckEnum;
use App\Enums\OpenShop\InvestmentPromotion\SignOrderEnum;
use App\Models\Check\CheckStreamModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopSignOrderModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopSignOrderPayHistoryModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopSpaceDesignCostMappingModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopSpaceDesignSoftOutfitMappingModel;
use App\Service\Check\CheckStreamParam;
use Illuminate\Support\Collection;

abstract class BaseKfDataSource
{
    protected Collection       $lists;
    protected CheckStreamParam $checkStreamParam;

    public function setCheckStreamParam(CheckStreamParam $param): self
    {
        $this->checkStreamParam = $param;
        return $this;
    }

    /**
     * 生成lists
     *
     * 约定lists中必须包含sysType、orderId
     * @param int $pageNum
     * @param int $pageSize
     * @return bool
     */
    abstract public function generateLists(int $pageNum, int $pageSize): bool;

    abstract public function transfer($item): array;

    public static function classLists(): Collection
    {
        return collect([
            KfRmsPayStream::class,
            KfOpenShopBankTransfer::class,
        ]);
    }

    public function addKfDataSource(): void
    {
        $pageNum  = 1;
        $pageSize = 200;

        do {
            $this->lists = collect();
            $hasMore     = $this->generateLists($pageNum, $pageSize);

            if ($this->lists->count()) {

                // 根据业务过滤掉明细
                $this->filterRubbishStream();

                CheckStreamModel::batchAddData($this->lists->map([$this, 'transfer']));
            }

            $pageNum++;
        } while ($hasMore);
    }

    /**
     * 根据业务过滤掉明细
     * @return void
     */
    private function filterRubbishStream()
    {
        // TODO sysType多了，要写下去

        $rubbishIds = [];
        foreach (CheckEnum::CHECK_SYS_TYPES as $sysType) {
            $orderIds = $this->lists->where('sysType', $sysType)->pluck('orderId');

            switch ($sysType) {
                case CheckEnum::SYS_TYPE_OPEN_SHOP_LEAGUE:
                    $rubbishIds = array_merge($rubbishIds,
                        OpenShopSignOrderModel::query()
                                              ->whereIn('orderNo', $orderIds)
                                              ->where('status',
                                                  SignOrderEnum::ORDER_STATUS_NO)
                                              ->pluck('orderNo')
                                              ->toArray());
                    break;
                case CheckEnum::SYS_TYPE_OPEN_SHOP_DESIGN:
                    $rubbishIds = array_merge($rubbishIds,
                        OpenShopSpaceDesignCostMappingModel::query()
                                                           ->withoutGlobalScope('isDel')
                                                           ->with([
                                                               'signOrderRel' => function ($query) {
                                                                   $query->where('status',
                                                                       SignOrderEnum::ORDER_STATUS_NO);
                                                               }
                                                           ])
                                                           ->whereIn('preparationNo', $orderIds)
                                                           ->select('preparationNo', 'orderNo')
                                                           ->get()
                                                           ->filter(function ($item) {
                                                               if ($item->signOrderRel) {
                                                                   return true;
                                                               }

                                                               return false;
                                                           })
                                                           ->pluck('preparationNo')
                                                           ->toArray());
                    break;
                case CheckEnum::SYS_TYPE_OPEN_SHOP_EQUIPMENT:
                    $rubbishIds = array_merge($rubbishIds,
                        OpenShopSignOrderPayHistoryModel::query()
                                                        ->with([
                                                            'signOrderRel' => function ($query) {
                                                                $query->where('status', SignOrderEnum::ORDER_STATUS_NO);
                                                            }
                                                        ])
                                                        ->whereIn('bizId', $orderIds)
                                                        ->select('bizId', 'orderNo')
                                                        ->get()
                                                        ->filter(function ($item) {
                                                            if ($item->signOrderRel) {
                                                                return true;
                                                            }

                                                            return false;
                                                        })
                                                        ->pluck('bizId')
                                                        ->toArray()
                    );
                    break;
                case CheckEnum::SYS_TYPE_OPEN_SHOP_DECORATE:
                    $rubbishIds = array_merge($rubbishIds,
                        OpenShopSpaceDesignSoftOutfitMappingModel::query()
                                                                 ->withoutGlobalScope('isDel')
                                                                 ->with([
                                                                     'signOrderRel' => function ($query) {
                                                                         $query->where('status',
                                                                             SignOrderEnum::ORDER_STATUS_NO);
                                                                     }
                                                                 ])
                                                                 ->whereIn('preparationNo', $orderIds)
                                                                 ->select('preparationNo', 'orderNo')
                                                                 ->get()
                                                                 ->filter(function ($item) {
                                                                     if ($item->signOrderRel) {
                                                                         return true;
                                                                     }

                                                                     return false;
                                                                 })
                                                                 ->pluck('preparationNo')
                                                                 ->toArray()

                    );
                    break;
                case CheckEnum::SYS_TYPE_ANNUAL_FEE:
                case CheckEnum::SYS_TYPE_AGAINST:
                    break;
            }

            // 过滤所有测试店铺下的订单
            OpenShopSignOrderPayHistoryModel::query()
                                            ->with('signOrderRel')
                                            ->whereIn('bizId', $orderIds)
                                            ->get()
                                            ->each(function ($item) use (&$rubbishIds) {
                                                if (!$item->signOrderRel) {
                                                    return;
                                                }

                                                if ($item->signOrderRel->shopCode >= OpenShopSignOrderModel::SHOP_CODE_TEST) {
                                                    $rubbishIds[] = $item->bizId;
                                                }
                                            });
        }

        $this->lists = $this->lists
            ->filter(function ($item) use ($rubbishIds) {
                if (!$item['orderId']) {
                    return false;
                }

                if (in_array($item['orderId'], $rubbishIds)) {
                    return false;
                }

                return true;
            })
            ->values();
    }
}
